#include <algorithm>
#include <buffer.h>
#include <cassert>
#include <cstddef>
#include <string>
#include <string.h>

namespace muduo
{
    Buffer::Buffer():_read_index(0),_write_index(0),_buffer(MAXNUM){}
    char* Buffer::Begin(){return &*_buffer.begin();}
    uint64_t Buffer::BufferSize(){return _buffer.size();}
    char* Buffer::GetReadIndex(){return Begin()+_read_index;}
    char* Buffer::GetWriteIndex(){return Begin()+_write_index;}
    uint64_t Buffer::ReadFrontSpace(){return _read_index;}
    uint64_t Buffer::WriteTailSpace(){return _buffer.size()-_write_index;}
    uint64_t Buffer::EnableReadSize(){return _write_index-_read_index;}
    void Buffer::MoveReadidx(uint64_t len){
        if(len == 0) return;
        assert(len<=EnableReadSize());
        _read_index += len;
    }
    void Buffer::MoveWriteidx(uint64_t len){
        if(len == 0) return;
        assert(len<=WriteTailSpace());
        _write_index += len;
    }
    void Buffer::EnsureSpace(uint64_t len){
        if(WriteTailSpace() >= len) return;
        // 移动
        if(WriteTailSpace() + ReadFrontSpace() >= len){
            // 记录可读空间大小
            uint64_t _size = EnableReadSize();
            std::copy(GetReadIndex(),GetReadIndex()+_size,Begin());
            _read_index=0;
            _write_index = _size;
        }
        // 扩容
        else{
            // 这样的扩容方式势必会造成多次扩容，原地扩容还好，异地扩容需要大量的拷贝
            // _buffer.resize(_write_index + len);
            _buffer.resize(_buffer.size()*1.5);
        }
    }
    void Buffer::Read(void* buff,uint64_t len){
        assert(len <= EnableReadSize());
        std::copy(GetReadIndex(),GetReadIndex()+len,(char*)buff);
    }
    void Buffer::ReadAndPop(void* buff,uint64_t len){
        Read(buff,len);
        MoveReadidx(len);
    }
    std::string Buffer::ReadAsString(uint64_t len){
        assert(len <= EnableReadSize());
        std::string str;
        str.resize(len);
        Read(&str[0],len);
        return str;
    }
    std::string Buffer::ReadAsStringAndPop(uint64_t len){
        std::string str = ReadAsString(len);
        MoveReadidx(len);
        return str;
    }
    void Buffer::Write(const void* data,uint64_t len){
        if(len==0) return;
        EnsureSpace(len);
        std::copy((const char*)data,(const char*)data+len,GetWriteIndex());
    }
    void Buffer::WriteAndPush(const void* data,uint64_t len){
        if(len == 0){return;}
        Write(data,len);
        MoveWriteidx(len);
    }
    // =======================
    void Buffer::WriteAsString(const std::string& str){
        uint64_t len = str.size();
        Write(&str[0],len);
    }
    void Buffer::WriteAsStringAndPush(const std::string& str){
        WriteAsString(str);
        MoveWriteidx(str.size());
    }
    void Buffer::WriteAsBuffer(Buffer& buf){
        Write(buf.GetReadIndex(), buf.EnableReadSize());
    }
    void Buffer::WriteAsBufferAndPush(Buffer& buf){
        WriteAsBuffer(buf);
        MoveWriteidx(buf.EnableReadSize());
    }
    char* Buffer::FindCRLF(){
        char *res = (char*)memchr(GetReadIndex(),'\n',EnableReadSize());
        return res;
    }
    std::string Buffer::GetLine(){
        char* pos = FindCRLF();
        if(pos==nullptr) return "";
        return ReadAsString(pos-GetReadIndex()+1);
    }
    std::string Buffer::GetLineAndPop(){
        std::string str = GetLine();
        MoveReadidx(str.size());
        return str;
    }
    void Buffer::clear(){
        _read_index=0;
        _write_index=0;
    }


}   